<template>
  <div class="fc-style">
    <n-layout has-sider position="absolute">
      <n-layout-sider bordered width="240">
        <div class="components">
          <ComponentGroup
              title="基础组件"
              :fields="basicFields"
              :list="naiveui.basicComponents"
          />
          <ComponentGroup
              title="高级组件"
              :fields="advanceFields"
              :list="naiveui.advanceComponents"
          />
          <ComponentGroup
              title="布局组件"
              :fields="layoutFields"
              :list="naiveui.layoutComponents"
          />
          <ComponentGroup
              title="其它组件"
              :fields="otherFields"
              :list="naiveui.otherComponents"
          />
        </div>
      </n-layout-sider>
      <n-layout >
        <NaiveHeader style="height: 42px;line-height: 50px;border-bottom: 1px solid #e4e7ed;text-align: right;padding: 0 10px;"
                     v-bind="$props"
                     @preview="() => (previewVisible = true)"
                     @uploadJson="() => (uploadJsonVisible = true)"
                     @generateJson="handleGenerateJson"
                     @generateCode="handleGenerateCode"
                     @clearable="handleClearable"
        >
          <slot name="header"></slot>
        </NaiveHeader>
        <n-layout has-sider position="absolute" style="top: 45px;">
          <DesignForm
              ref="widgetFormRef"
              v-model:widgetForm="widgetForm"
              v-model:widgetFormSelect="widgetFormSelect"
          />
        </n-layout>
      </n-layout>
      <n-layout-sider
          bordered
          class="widget-config-container"
          content-style="border-left: 1px solid #e4e7ed"
          width="400"
      >
      <n-layout-content class="config-content">
          <n-tabs type="line">
            <n-tab-pane name="widget" tab="字段属性">
              <DesignConfig v-model:select="widgetFormSelect" />
            </n-tab-pane>
            <n-tab-pane name="form" tab="表单属性">
              <NaiveFormConfig v-model:config="widgetForm.config" />
            </n-tab-pane>
          </n-tabs>
        </n-layout-content> 
      </n-layout-sider>
    </n-layout>
    <n-modal
        v-model:show="uploadJsonVisible"
        title="导入JSON"
        preset="dialog"
        style="width:800px"
        positive-text="确定"
        negative-text="取消"
        @positive-click="handleUploadJson"
    >
      <n-alert
          type="info"
          style="margin-bottom: 10px"
      >JSON格式如下，直接复制生成的json覆盖此处代码点击确定即可</n-alert>
      <CodeEditor v-model:value="jsonEg" language="json" />
    </n-modal>
    <n-modal v-model:show="previewVisible" preset="dialog" title="预览" style="width: max-content;max-width:100vw;min-width: 500px;overflow: auto">
      <!--      <template #header>-->
      <!--        <div>标题</div>-->
      <!--      </template>-->
      <div>
        <GenerateForm
            style="margin-top: 20px"
            ref="generateFormRef"
            :data="widgetForm"
        />
      </div>
      <template #action>
        <div>
          <n-space>
            <n-button @click="handleReset">重置校验</n-button>
            <n-button type="primary" @click="handleGetData">获取数据</n-button>
          </n-space>
        </div>
      </template>
    </n-modal>


    <n-modal
        v-model:show="generateJsonVisible"
        preset="dialog"
        title="生成JSON"
        positive-text="Copy"
        negative-text="关闭"
        style="width: 800px"
        @positive-click="handleCopyClick(generateJsonTemplate)"
    >
      <div>
        <CodeEditor :value="generateJsonTemplate" language="json" readonly />
      </div>
    </n-modal>

    <n-modal
        v-model:show="dataJsonVisible"
        preset="dialog"
        title="获取数据"
        positive-text="Copy"
        negative-text="关闭"
        style="width: 800px"
        @positive-click="handleCopyClick(dataJsonTemplate)"
    >
      <CodeEditor :value="dataJsonTemplate" language="json" readonly />
    </n-modal>

    <n-modal
        v-model:show="dataCodeVisible"
        preset="dialog"
        title="生成代码"
        positive-text="Copy"
        negative-text="关闭"
        style="width: 800px"
        @positive-click="handleCopyClick(dataCodeTemplate)"
    >
      <n-tabs
          type="card"
          v-model:value="codeLanguage"
          :tabBarStyle="{ margin: 0 }"
      >
        <n-tab-pane tab="页面表单" :name="codeType.Form">
          <CodeEditor :value="dataCodeTemplate" language="html" readonly />
        </n-tab-pane>
        <n-tab-pane tab="弹窗表单" :name="codeType.Model">
          <CodeEditor :value="dataCodeTemplate" language="html" readonly />
        </n-tab-pane>
      </n-tabs>
    </n-modal>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, PropType, toRefs, watchEffect } from 'vue'
import { useMessage } from 'naive-ui'
import { merge } from 'lodash'
import CodeEditor from './components/CodeEditor.vue'
import ComponentGroup from './components/ComponentGroup.vue'
import NaiveHeader from './components/NaiveHeader.vue'
import DesignForm from './components/design/DesignForm.vue'
import GenerateForm from './components/generate/GenerateForm.vue'
import DesignConfig from './components/design/DesignConfig.vue'
import NaiveFormConfig from './components/NaiveFormConfig.vue'
import { naiveui } from './config'
import { copy } from './utils'
import { CodeType, PlatformType } from './enums'
import generateCode from './utils/generateCode'

export default defineComponent({
  name: 'FormDesign',
  components: {
    NaiveHeader,
    ComponentGroup,
    CodeEditor,
    DesignForm,
    GenerateForm,
    DesignConfig,
    NaiveFormConfig
  },
  props: {
    preview: {
      type: Boolean,
      default: true
    },
    generateCode: {
      type: Boolean,
      default: true
    },
    generateJson: {
      type: Boolean,
      default: true
    },
    uploadJson: {
      type: Boolean,
      default: true
    },
    clearable: {
      type: Boolean,
      default: true
    },
    basicFields: {
      type: Array as PropType<Array<string>>,
      default: () => [
        'input',
        'number',
        'radio',
        'checkbox',
        'time',
        'date',
        'rate',
        'select',
        'switch',
        'slider',
        'color',
      ]
    },
    advanceFields: {
      type: Array as PropType<Array<string>>,
      default: () => [
        'upload',
        'richtext-editor',
        'cascader',
        'tree',
        'dynamicTable',
        'selectTree',
        'transfer',
        'dynamicTags',
      ]
    },
    layoutFields: {
      type: Array as PropType<Array<string>>,
      default: () => ['grid','table',]
    },
    otherFields: {
      type: Array as PropType<Array<string>>,
      default: () => ['text','alert','divider','button']
    }
  },
  setup() {
    const message = useMessage()

    let widgetForm = JSON.parse(JSON.stringify(naiveui.widgetForm));
    for (let key in naiveui.widgetForm) {
      if (naiveui.widgetForm.hasOwnProperty(key)) {
        if(typeof naiveui.widgetForm[key] === 'function') {
          widgetForm[key] = naiveui.widgetForm[key];
        }
      }
    }

    const state = reactive({
      naiveui,
      codeType: CodeType,
      widgetForm: widgetForm,
      widgetFormSelect: undefined,
      generateFormRef: null as any,
      configTab: 'widget',
      previewVisible: false,
      uploadJsonVisible: false,
      dataJsonVisible: false,
      dataCodeVisible: false,
      generateJsonVisible: false,
      generateCodeVisible: false,
      generateJsonTemplate: JSON.stringify(naiveui.widgetForm, null, 2),
      dataJsonTemplate: '',
      dataCodeTemplate: '',
      codeLanguage: CodeType.Form,
      jsonEg: JSON.stringify(naiveui.widgetForm, null, 2)
    })

    const handleUploadJson = () => {
      try {
        setJson(JSON.parse(state.jsonEg))
        state.uploadJsonVisible = false
        message.success('上传成功')
      } catch (error) {
        message.error('上传失败')
      }
    }

    const handleCopyClick = (text: string) => {
      copy(text)
      message.success('Copy成功')
    }

    const handleGetData = () => {
      state.generateFormRef.getData().then((res: any) => {
        state.dataJsonTemplate = JSON.stringify(res, null, 2)
        state.dataJsonVisible = true
      })
    }

    const handleGenerateJson = () =>
        (state.generateJsonTemplate = JSON.stringify(
            state.widgetForm,
            null,
            2
        )) && (state.generateJsonVisible = true)

    const handleGenerateCode = () => {
      state.codeLanguage = CodeType.Form
      state.dataCodeVisible = true
    }

    watchEffect(() => {
      if (state.dataCodeVisible) {
        state.dataCodeTemplate = generateCode(
            state.widgetForm,
            state.codeLanguage,
            PlatformType.NaiveUi
        )!
      }
    })

    const handleClearable = () => {
      state.widgetForm.list = []
      merge(state.widgetForm, JSON.parse(JSON.stringify(naiveui.widgetForm)))
      state.widgetFormSelect = undefined
    }

    const handleReset = () => state.generateFormRef.reset()

    const getJson = () => state.widgetForm

    const setJson = (json: naiveui.WidgetForm) => {
      state.widgetForm.list = []
      merge(state.widgetForm, json)
      if (json.list.length) {
        state.widgetFormSelect = json.list[0]
      }
    }

    const getTemplate = (codeType: CodeType) =>
        generateCode(state.widgetForm, codeType, PlatformType.NaiveUi)

    const clear = () => handleClearable()

    return {
      ...toRefs(state),
      handleUploadJson,
      handleCopyClick,
      handleGetData,
      handleGenerateJson,
      handleGenerateCode,
      handleClearable,
      handleReset,
      getJson,
      setJson,
      getTemplate,
      clear
    }
  }
})
</script>
